#include "stm32f10x.h"                  // Device header
#include "Delay.h"

#define MyI2C_SCL GPIO_Pin_10
#define MyI2C_SDA GPIO_Pin_11

#define Write 0
#define Read 1

void MyI2C_W_SCL(uint8_t BitVal)
{
    GPIO_WriteBit(GPIOB, MyI2C_SCL, (BitAction)BitVal);
    Delay_us(10);
}


void MyI2C_W_SDA(uint8_t BitVal)
{
    GPIO_WriteBit(GPIOB, MyI2C_SDA, (BitAction)BitVal);
    Delay_us(10);
}

//开漏输出同时也能输入 (高阻态的时候可以吧也许)
uint8_t MyI2C_R_SDA(void)
{
    Delay_us(10);
    return GPIO_ReadInputDataBit(GPIOB, MyI2C_SDA);
}
//MyI2C是自制I2C通信，是软件模拟的
//MyI2C比较底层，协议层


void MyI2C_Init(void)
{
    //使用两个GPIO口的高低电平变化来模拟I2C
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);

    GPIO_InitTypeDef GPIO_InitStruct = 
    {
        .GPIO_Mode = GPIO_Mode_Out_OD,
        .GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11,
        .GPIO_Speed = GPIO_Speed_50MHz
    };
    GPIO_Init(GPIOB, &GPIO_InitStruct);

}


//Start需要在SCL High 期间SDA产生Falling
void MyI2C_Start(void)
{
    MyI2C_W_SDA(1);
    MyI2C_W_SCL(1);
    MyI2C_W_SDA(0);
    MyI2C_W_SCL(0);
}
//Stop 需要在SCL Low 期间SDA产生Rising
void MyI2C_Stop(void)
{
    MyI2C_W_SDA(0);
    MyI2C_W_SCL(1);
    MyI2C_W_SDA(1);
}

//前7位是外设地址，像是MPU6050啊
//八位数据前七位是地址，后一位是Read or Write
//Address输入的时候是地址放在高七位的 16进制数据
//再或(|)上一个R_W Write是0 Read是1
void MyI2C_SetAddress_R_W(uint8_t Slave_Address, uint8_t R_W)
{
    //逐字节发送，从高到低
    uint8_t i = 0;
    uint8_t Address = Slave_Address | R_W;
    for (i = 0; i < 8; i ++)
    {

        //用按位与依次取出每一位
        //用i 和 <<来调整取出的位
        MyI2C_W_SDA(Address & (0x01 << (7 - i)));
        
        MyI2C_W_SCL(1);
        MyI2C_W_SCL(0);
    }
}

void MyI2C_SetRegAddress(uint8_t RegAddress)
{
    //逐字节发送，从高到低
    uint8_t i = 0;
    for (i = 0; i < 8; i ++)
    {

        //用按位与依次取出每一位
        //用i 和 <<来调整取出的位
        MyI2C_W_SDA(RegAddress & (0x01 << (7 - i)));

        MyI2C_W_SCL(1);
        MyI2C_W_SCL(0);
    }
}

//发送一个字节的数据
void MyI2C_SendByte(uint8_t DataByte) 
{
    //逐字节发送，从高到低
    uint8_t i = 0;
    for (i = 0; i < 8; i ++)
    {

        //用按位与依次取出每一位
        //用i 和 <<来调整取出的位
        MyI2C_W_SDA(DataByte & (0x01 << (7 - i)));

        MyI2C_W_SCL(1);
        MyI2C_W_SCL(0);
    }
}

//主机应答0应答 1不应答
//主机停止接收数据就给1 不理从机就行
//Bitval 选择继续接收或者不接收 0为Continue 1为Stop
void MyI2C_SendAck(uint8_t AckBit)
{
    MyI2C_W_SDA(AckBit);
    MyI2C_W_SCL(1);
    MyI2C_W_SCL(0);
}

//主机松开SDA 从机拉低SDA（从机拉低就是应答了），最后从机再自动释放就OK啦
uint8_t MyI2C_ReceiveAck(void)
{
    uint8_t AckBit;
    //主机释放，让从机操控SDA
    MyI2C_W_SDA(1);
    MyI2C_W_SCL(1);
    AckBit = MyI2C_R_SDA();
    MyI2C_W_SCL(0);
    return AckBit;
}


//稍微复杂一点
uint8_t MyI2C_ReceiveByte(void)
{
    uint8_t Receive_Byte = 0;
    //逐字节接收，从高到低
    uint8_t i = 0;
    //主机释放SDA，从机可以放数据
    MyI2C_W_SDA(1);
    for (i = 0; i < 8; i ++)
    {

        MyI2C_W_SCL(1);

        //SCL拉低 SCL释放 读取SDA
        //用按位或依次接收每一位
        //用i 和 <<来调整接收的位
        Receive_Byte |= (MyI2C_R_SDA() << (7 - i));   
         
        MyI2C_W_SCL(0);
    }
    return Receive_Byte;
}
